Shader基础技巧整理 您所在的位置:网站首页 unity shader入门精要pdf Shader基础技巧整理

Shader基础技巧整理

2023-04-29 00:12| 来源: 网络整理| 查看: 265

【GT】Assembler 源码解读及使用 !Cocos Creator! 的作者也开了自己公众号啦!

自从接触了shader之后我便深深得爱上了它,因为它独特的编程思考方式冲击着我这十几年的惯性认知。

在向各位大佬学习的过程中,每学到一个新的技巧,我都不禁感叹:“实在是妙!”

本文将整理一些个人常用的shader技巧/方法,只包含片元着色器相关内容。

由于本人尚属初学,所以内容会比较基础。

简单几何图形 区间(带通)

Shader基础技巧整理_旋转矩阵

两个阶梯函数叠加构成的带通函数,用数字信号处理的角度去思考貌似是个不错的选择

float Band(float v, float start, float end) { float up = step(start, v); float down = 1.0 - step(end, v); return up * down;}矩形

Shader基础技巧整理_#define_02

x, y两个方向的带通函数叠加

float Rect(vec2 uv, float l, float b, float r, float t) { float x = Band(uv.x, l, r); float y = Band(uv.y, b, t); return x * y;}圆形

Shader基础技巧整理_2d_03

圆形比较容易出现锯齿,所以用 ​​smoothstep​​ 做平滑处理。

由于 ​​distance()​​ 依赖 ​​sqrt()​​ 开根号,在一些老硬件上会比较耗时,实际使用时可以考虑转换为和r平方进行比较的公式。

float Circle(vec2 uv, vec2 o, float r, float blur) { return smoothstep(r, r-blur, distance(uv, o));}混合叠加

上述几何图形函数的输出值是0或1的float(经过 ​​smoothstep()​​ 可能会出现中间值,不过此处可以不考虑)。

0或1的float值可以利用加、减、乘来模拟位运算。比如上述区间、矩形几何图形都是通过乘法叠加。

加减法例子:ET脸

Shader基础技巧整理_旋转矩阵_04

画一个大圆当脸,减去两个小圆当眼睛

float ETFace(vec2 uv, vec2 o) { float c = Circle(uv, vec2(.0, .0), 0.5, 0.01); c -= Circle(uv, vec2(-.2, -.2), 0.2, 0.01); c -= Circle(uv, vec2(.2, -.2), 0.2, 0.01); return c;} 坐标空间处理

Cocos Creator以 ​​左上角​​ 为坐标原点,范围(0, 1)。

shadertoy, GlslEditor中均以 ​​左下角​​ 为坐标原点,范围(0, 1),接下来所有代码将使用这个坐标系。

在绘制某些对称图形时可能需要将原点调整到屏幕中心,即将(0, 1)区间映射到(-0.5, 0.5)。

根据不同场景也可以将(0, 1)区间映射到(-1, 1),哪个处理起来方便用哪个。

// (0, 1)区间映射到(-1, 1)uv = uv * 2.0 - 1.0;

也可以用下面的方法从任意区间映射到任意区间

float Remap01(float a, float b, float t) { return (t-a) / (b-a);}float Remap(float a, float b, float c, float d, float t) { return Remap01(a, b, t) * (d-c) + c;}长宽适配

不知道这个功能的简称是什么,暂且这么称呼吧。

其作用是在分辨率长宽不等的情况下将坐标空间映射为等边,映射后原先较长的一边其自变量区间会被放大。

Shader基础技巧整理_旋转矩阵_05

void main() { vec2 uv = gl_FragCoord.xy/u_resolution.xy; uv = uv * 2.0 - 1.0; // 位移到以中间为原点 uv.x *= u_resolution.x/u_resolution.y; // 将x的自变量区间拉长 float mask = Rect(uv, -0.5, -0.5, 0.5, 0.5); vec3 color = vec3(mask); gl_FragColor = vec4(color,1.0);}计算角度

Shader基础技巧整理_#define_06

用​​atan()​​ 计算角度,图中将(-PI, PI)区间映射到(0, 1)区间,并且将值对应的灰度输出。

​​atan()​​ 计算比较耗时,实际项目中慎用。

#define PI 3.141592653589793void main() { vec2 uv = gl_FragCoord.xy/u_resolution.xy; uv = uv * 2.0 - 1.0; uv.x *= u_resolution.x/u_resolution.y; float angle = atan(uv.y, uv.x); angle = Remap(-PI, PI, 0., 1.0, angle); vec3 color = vec3(angle); gl_FragColor = vec4(color,1.0);}旋转

Shader基础技巧整理_2d_07

uv乘以旋转矩阵

#define PI 3.141592653589793mat2 Rotate2d(float angle){ return mat2(cos(angle), -sin(angle), sin(angle), cos(angle));}void main() { vec2 uv = gl_FragCoord.xy/u_resolution.xy; uv = uv * 2.0 - 1.0; uv.x *= u_resolution.x/u_resolution.y; uv = Rotate2d(PI / 6.) * uv; float mask = Rect(uv, -0.5, -0.5, 0.5, 0.5); vec3 color = vec3(mask); gl_FragColor = vec4(color,1.0);}网格化

Shader基础技巧整理_#define_08

将屏幕分割成5x5个网格,每个格子里画一个圆。

原理是将uv拉伸5倍后取小数部分,这样处理后uv会变成每个网格内的局部坐标,这个技巧被广泛使用。

void main() { // ... uv = fract(uv * 5.); float mask = Circle(uv, vec2(0.5), 0.5, 0.01); // ...} 噪音(随机化hash)

Shader基础技巧整理_#define_09

获取噪音的方法很多很灵活,输入一般是和uv相关的变量,输出(0, 1)范围的1维或2维值。

只要让人肉眼难分辨出模式,就是一个好用的噪音函数。

噪音的用途非常广泛,可以利用噪音降低图片的人工痕迹,后面会单独整理一篇文章。

float Noise1(vec2 p) { return fract(sin( dot(p, vec2(12.9898,78.233)) ) * 43758.5453123);}float Noise2(vec2 p) { p = frac(p * vec2(123.34, 345.45)); p += dot(p, p + 34.345); return frac(p.x * p.y);}



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有